home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / processes / pthreadsorts / sortablepicture.cp < prev    next >
Encoding:
Text File  |  2000-10-06  |  16.2 KB  |  429 lines

  1. /*
  2.     File:        SortablePicture.cp
  3.  
  4.     Contains:    Methods for the SortablePicture Abstract base class.
  5.  
  6.     Written by:     Karl Groethe
  7.  
  8.     Copyright:    Copyright © 2000 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.             You may incorporate this Apple sample source code into your program(s) without
  11.             restriction. This Apple sample source code has been provided "AS IS" and the
  12.             responsibility for its operation is yours. You are not permitted to redistribute
  13.             this Apple sample source code as "Apple sample source code" after having made
  14.             changes. If you're going to re-distribute the source, we require that you make
  15.             it clear in the source that the code was descended from Apple sample source
  16.             code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                         7/00    Created
  20. */
  21. #include "SortablePicture.h"
  22. #include <Carbon/Carbon.h>
  23. #include <unistd.h>
  24.  
  25. const UInt32 textSize=9;
  26.  
  27. SortablePicture::SortablePicture(ResID inPictID)
  28. {
  29.     /*------------------------------------------------------
  30.        Constructure for creating a sortable picture from the
  31.        pict resources specified by inPictID
  32.     --------------------------------------------------------*/
  33.     pictID=inPictID;
  34.     ShowStats=FALSE;
  35.     FrameWaitTime.tv_sec=0;
  36.     FrameWaitTime.tv_nsec=NSEC_PER_SEC/6;//6 fps
  37.     
  38.     #ifdef SPEED_CONTROL
  39.     SwapWaitTime.tv_sec=0;
  40.     SwapWaitTime.tv_nsec=0;
  41.     #endif
  42.     
  43.     AllocPictGWorld();
  44.     CreatePictWindow();
  45.     AllocPixelArrays();
  46.     
  47.     pthread_mutex_init(&mutex,NULL);//initialize a pthread mutex
  48.     pthread_cond_init(&refresh,NULL);//initialize the conditional for pthread_timedwait()
  49.     
  50.     //might as well just lock down our pixmap now
  51.     //We'll be using it a lot
  52.     LockPixels(GetPortPixMap(pictGWorld));
  53.     //base address won't change so lets store it.
  54.     pictBaseAddr=GetPixBaseAddr(GetPortPixMap(pictGWorld));
  55.     //create our thread to scramble and sort picture
  56.     pthread_create(&scrambleAndSortThread,
  57.                     NULL,
  58.                     SortablePicture::ScrambleAndSortThread,
  59.                     this);
  60.     //create thread to handle drawing
  61.     pthread_create(&drawThread,
  62.                     NULL,
  63.                     SortablePicture::DrawThread,
  64.                     this);
  65. }
  66. SortablePicture::~SortablePicture()
  67. {
  68.     /*------------------------------------------------------
  69.         Destructor for our sortable picture, handle 
  70.         canceling and joining threads and disposing of 
  71.         allocated memory.
  72.     --------------------------------------------------------*/
  73.     #ifdef SPEED_CONTROL
  74.     SetSwapWaitTime(0);//don't want to wait while we cancel threads
  75.     #endif
  76.     pthread_cancel(drawThread);
  77.     pthread_join(drawThread,NULL);
  78.     pthread_cancel(scrambleAndSortThread);
  79.     pthread_join(scrambleAndSortThread,NULL);
  80.     pthread_mutex_destroy(&mutex);
  81.     pthread_cond_destroy(&refresh);
  82.     //unlock our pixmap before we go
  83.     UnlockPixels(GetPortPixMap(pictGWorld));
  84.     DisposePixelArrays();
  85.     DisposePictWindow();
  86.     DisposePictGWorld();
  87. }
  88. void* SortablePicture::ScrambleAndSortThread(void* inPict)
  89. {
  90.     /*------------------------------------------------------
  91.         Static C++ member that handles Scrambling and sorting
  92.         our picture from within a thread.
  93.     --------------------------------------------------------*/
  94.     while(TRUE)
  95.     {
  96.         sleep(2);//show the sorted picture for a few secs
  97.         ((SortablePicture*)inPict)->Scramble();
  98.         ((SortablePicture*)inPict)->Sort();
  99.     }
  100.     return 0;
  101. }
  102. void* SortablePicture::DrawThread(void* inPict)
  103. {
  104.     /*------------------------------------------------------
  105.         Static C++ member that handles Drawing
  106.         our picture from within a thread.
  107.     --------------------------------------------------------*/
  108.     while(TRUE){
  109.         ((SortablePicture*)inPict)->Draw();
  110.     }
  111.     return 0;
  112. }
  113. void SortablePicture::CreatePictWindow()
  114. {
  115.     /*------------------------------------------------------
  116.       Create our picture's window.
  117.     --------------------------------------------------------*/
  118.     static EventTypeSpec closeEvent={kEventClassWindow,kEventWindowClose};
  119.         
  120.     SortablePicture*    temp=this;
  121.     Rect portBounds;
  122.     GetPortBounds(pictGWorld,&portBounds);
  123.     CreateNewWindow(kDocumentWindowClass,
  124.                     kWindowCollapseBoxAttribute | 
  125.                     kWindowCloseBoxAttribute |
  126.                     kWindowStandardHandlerAttribute, 
  127.                     &portBounds, &pictWindow);
  128.     MoveWindow(pictWindow,100,100,FALSE);
  129.     
  130.     SetWindowProperty(    pictWindow,
  131.                         kAppCreator,
  132.                         Class_ID,
  133.                         sizeof(SortablePicture*),
  134.                         &temp);//attach our object to the window as a property
  135.     //install a carbon event handler to handle disposing of our object when the window is closed
  136.     InstallWindowEventHandler(pictWindow,NewEventHandlerUPP(myWindowCloseHandler),
  137.                             1,&closeEvent,0,NULL);
  138.     ShowWindow(pictWindow);
  139.  
  140. }
  141. void SortablePicture::DisposePictWindow()
  142. {
  143.     /*------------------------------------------------------
  144.         message that can be sent to an object to tell it to
  145.         dispose of it's window
  146.     --------------------------------------------------------*/
  147.         DisposeWindow(pictWindow);
  148. }
  149. void SortablePicture::AllocPictGWorld()
  150. {    
  151.     /*------------------------------------------------------
  152.         Create a gworld where we can manipulate the pixmap
  153.         of our picture.
  154.     --------------------------------------------------------*/
  155.     GrafPtr    origPort;
  156.     GDHandle    origDev;
  157.     pictBounds=(*GetPicture(pictID))->picFrame;
  158.     pictWidth=pictBounds.right-pictBounds.left;
  159.     pictHeight=pictBounds.bottom-pictBounds.top;
  160.     GetGWorld(&origPort,&origDev);
  161.     NewGWorld(&pictGWorld,0,&pictBounds,NULL,NULL,0);
  162.     SetGWorld(pictGWorld,NULL);
  163.     DrawPicture(GetPicture(pictID),&pictBounds);
  164.     SetGWorld(origPort,origDev);
  165. }
  166. void SortablePicture::DisposePictGWorld()
  167. {
  168.     /*------------------------------------------------------
  169.        Dispose of our gworld
  170.     --------------------------------------------------------*/
  171.     DisposeGWorld(pictGWorld);
  172. }
  173. void SortablePicture::AllocPixelArrays()
  174. {
  175.     /*------------------------------------------------------
  176.        Allocate and initialize the arrays we will use for
  177.        scrambling and sorting the picture.
  178.     --------------------------------------------------------*/
  179.     linearPictSize=pictWidth*pictHeight;
  180.     bytesPerPixel=GetPixDepth(GetPortPixMap(pictGWorld))/8;//depth in bytes
  181.     bytesPerRow=GetPixRowBytes(GetPortPixMap(pictGWorld)) & 0x7FFF;//strip off flags
  182.     
  183.     pixelIndexArray=new UInt32[linearPictSize];
  184.     pixelOffsetArray=new UInt32[linearPictSize];
  185.  
  186.     for(UInt32 i=0;i<pictHeight;i++)
  187.         for(UInt32 j=0;j<pictWidth;j++){
  188.             UInt32 index=i*pictWidth+j;//simple 2D indexing
  189.             pixelIndexArray[index]=index;//initial ordering of pixels so we know how to sort them
  190.             //offsets from the bass address so we can easily find pixels associated with each index
  191.             pixelOffsetArray[index]=i*bytesPerRow+j*bytesPerPixel;
  192.         }
  193. }
  194. void SortablePicture::DisposePixelArrays()
  195. {
  196.     /*------------------------------------------------------
  197.         Dispose of the arrays we used for scrambling and 
  198.         sorting our picture
  199.     --------------------------------------------------------*/
  200.     delete[] pixelIndexArray;
  201.     delete[] pixelOffsetArray;
  202. }
  203. void SortablePicture::SwapBytes(Byte* a,Byte* b,UInt32 numBytes)
  204. {
  205.     /*------------------------------------------------------
  206.        Utility function for swapping a set of bytes. This allows
  207.        us to deal with multiple bit depths without changing
  208.        any code.
  209.     --------------------------------------------------------*/
  210.     Byte c=0;
  211.     UInt32 i=0;
  212.     for(i=0;i<numBytes;i++){
  213.         c=a[i];
  214.         a[i]=b[i];
  215.         b[i]=c;
  216.     }
  217. }
  218. Boolean SortablePicture::InOrder(UInt32 indexA, UInt32 indexB)
  219. {
  220.     /*------------------------------------------------------
  221.         Comparison method used by subclassed to check if two
  222.         pixels are in order.  This also maintains a count of
  223.         how many comparisons have been made.
  224.     --------------------------------------------------------*/
  225.     comparisons++;
  226.     return (pixelIndexArray[indexA]<pixelIndexArray[indexB]);
  227. }
  228. void SortablePicture::SwapPixels(UInt32 indexA, UInt32 indexB)
  229. {
  230.     /*------------------------------------------------------
  231.        Swap method provided for subclasses to swap two pixels.
  232.        Swaps both the pixels and their index location and 
  233.        keeps track of the number of swaps that have been
  234.        made.
  235.     --------------------------------------------------------*/
  236.     
  237.     #ifdef SPEED_CONTROL
  238.     timespec wait=GetSwapWaitTime();
  239.     if(wait.tv_nsec>1)
  240.         pthread_cond_timedwait_relative_np(&refresh,&mutex,&wait);//wait for a signal
  241.     else
  242.          pthread_mutex_lock(&mutex);//block other threads while we swap pixels
  243.     #else
  244.     pthread_mutex_lock(&mutex);//block other threads while we swap pixels(no extra overhead)
  245.     #endif
  246.     //swap the pixels at indexA and indexB
  247.     SwapBytes(((Byte*)pictBaseAddr)+pixelOffsetArray[indexA],
  248.                 ((Byte*)pictBaseAddr)+pixelOffsetArray[indexB],bytesPerPixel);
  249.     //swap their index
  250.     SwapBytes((Byte*)&pixelIndexArray[indexA],
  251.             (Byte*)&pixelIndexArray[indexB],sizeof(UInt32));
  252.  
  253.     swaps++;//incriment swaps
  254.     pthread_mutex_unlock(&mutex);//release other threads
  255.     pthread_testcancel();//see if we should quit
  256. }
  257.     
  258. void SortablePicture::Scramble()
  259. {
  260.     /*------------------------------------------------------
  261.        Scramble the pixels of our picture
  262.     --------------------------------------------------------*/
  263.     for(UInt32 i=0;i<linearPictSize;i++)//use 2 Random to get full UInt32 Range
  264.         SwapPixels(i,((UInt32)Random()*(UInt32)Random())%linearPictSize);
  265.     swaps=lastSwapVal=0;
  266.     comparisons=0;
  267.     gettimeofday(&frameTime,NULL);//init frame time
  268. }
  269. void SortablePicture::UpdateStats()
  270. {
  271.      /*------------------------------------------------------
  272.        Update and draw the statistics for our picture
  273.     --------------------------------------------------------*/
  274.     Rect portBounds;
  275.     static const RGBColor textColor={0x0000,0x0000,0x0000};
  276.     GrafPtr    origPort;
  277.     RGBColor    oldColor;
  278.     timeval currentTime;
  279.     timeval difftime;
  280.     float fps,sps;
  281.     gettimeofday(¤tTime,NULL);
  282.     timersub(¤tTime,&frameTime,&difftime);
  283.     //calculate frames per second and don't bother if frametime is less than 1 second
  284.     fps=difftime.tv_sec>0 ? 1 : USEC_PER_SEC/(float)difftime.tv_usec;
  285.     sps=fps*(swaps-lastSwapVal);//calculate number of swaps per second
  286.     lastSwapVal=swaps;
  287.     frameTime=currentTime;
  288.     GetPort(&origPort);
  289.     SetPortWindowPort(pictWindow);
  290.     GetPortBounds(GetWindowPort(pictWindow),&portBounds);
  291.     GetForeColor(&oldColor);
  292.     RGBForeColor(&textColor);
  293.     TextSize(textSize);
  294.     TextFace(bold);
  295.     //name of the sort
  296.     CFStringRef sortString=CFStringCreateWithFormat(NULL,NULL,CFSTR("%s"),
  297.                             CFStringGetCStringPtr(GetSortName(),kCFStringEncodingMacRoman));
  298.     //total number of pixels
  299.     CFStringRef totalPixelString=CFStringCreateWithFormat(NULL,NULL,CFSTR("Pixels:%i"),linearPictSize);
  300.     //total number of comparisons
  301.     CFStringRef compareString=CFStringCreateWithFormat(NULL,NULL,CFSTR("Comparison:%i"),comparisons);
  302.     //total number of swaps
  303.     CFStringRef swapString=CFStringCreateWithFormat(NULL,NULL,CFSTR("Swap:%i"),swaps);
  304.     //frame rate and swap rate
  305.     CFStringRef FpsSpsString=CFStringCreateWithFormat(NULL,NULL,CFSTR("fps:%.1f\tsps:%.0f"),fps,sps);
  306.     MoveTo(portBounds.left+1,portBounds.bottom-1);
  307.     DrawString(CFStringGetPascalStringPtr(FpsSpsString,kCFStringEncodingMacRoman));
  308.     MoveTo(portBounds.left+1,portBounds.bottom-textSize-1);
  309.     DrawString(CFStringGetPascalStringPtr(swapString,kCFStringEncodingMacRoman));
  310.     MoveTo(portBounds.left+1,portBounds.bottom-2*textSize-1);
  311.     DrawString(CFStringGetPascalStringPtr(compareString,kCFStringEncodingMacRoman));
  312.     MoveTo(portBounds.left+1,portBounds.bottom-3*textSize-1);
  313.     DrawString(CFStringGetPascalStringPtr(totalPixelString,kCFStringEncodingMacRoman));
  314.     MoveTo(portBounds.left,portBounds.bottom-4*textSize-1);
  315.     DrawString(CFStringGetPascalStringPtr(sortString,kCFStringEncodingMacRoman));
  316.     RGBForeColor(&oldColor);
  317.     SetPort(origPort);
  318. }
  319. void SortablePicture::Draw()
  320. {
  321.     /*------------------------------------------------------
  322.        Draw our updated picture.
  323.     --------------------------------------------------------*/
  324.      GrafPtr    origPort;
  325.      GDHandle    origDev;
  326.      RgnHandle    visibleRgn=NewRgn();
  327.      GetGWorld(&origPort,&origDev);
  328.      Rect srcBounds,destBounds;
  329.      timespec wait=GetFrameWaitTime();
  330.      pthread_cond_timedwait_relative_np(&refresh,&mutex,&wait);//wait for a while
  331.      GetPortBounds(pictGWorld,&srcBounds);
  332.      GetWindowPortBounds(pictWindow,&destBounds);
  333.      SetGWorld(GetWindowPort(pictWindow),NULL);
  334.      CopyBits(    GetPortBitMapForCopyBits(pictGWorld),
  335.                 GetPortBitMapForCopyBits(GetWindowPort(pictWindow)),
  336.                 &srcBounds,
  337.                 &destBounds,
  338.                 srcCopy,NULL);
  339.     SetGWorld(origPort,origDev);
  340.     if(GetShowStats())
  341.         UpdateStats();
  342.     QDFlushPortBuffer(GetWindowPort(pictWindow),
  343.             GetPortVisibleRegion(GetWindowPort(pictWindow),visibleRgn));//flush the buffer
  344.     DisposeRgn(visibleRgn);
  345.     pthread_mutex_unlock(&mutex);//let our other threads go
  346.     pthread_testcancel();//see if we should quit
  347. }
  348. OSStatus SortablePicture::myWindowCloseHandler(EventHandlerCallRef inRef,
  349.                                                         EventRef inEvent,
  350.                                                         void* userData)
  351. {
  352.     /*------------------------------------------------------
  353.         Carbon Event handler for handling when our window is
  354.         closed.
  355.     --------------------------------------------------------*/
  356.     WindowRef window;
  357.     //get our window from the objed and dispose of it
  358.     GetEventParameter(inEvent,kEventParamDirectObject,typeWindowRef,NULL,sizeof(window),NULL,&window);
  359.     SortablePicture::DisposePictureWindow(window);
  360.     return noErr;
  361. }
  362.  
  363.  
  364. void SortablePicture::DisposePictureWindow(WindowRef window)
  365. {
  366.     /*------------------------------------------------------
  367.        Dispose of our window and the object associated with it
  368.     --------------------------------------------------------*/
  369.  
  370.     SortablePicture* mySortablePicture;
  371.     
  372.     GetWindowProperty( window,
  373.                         kAppCreator,
  374.                         Class_ID,
  375.                         sizeof(SortablePicture*),
  376.                         NULL,
  377.                         &mySortablePicture);
  378.     delete mySortablePicture;
  379. }
  380. Boolean SortablePicture::GetShowStats()
  381. {
  382.     /*------------------------------------------------------
  383.        Should we display the the statistics?
  384.     --------------------------------------------------------*/
  385.     return ShowStats;
  386. }
  387.  
  388. void SortablePicture::SetShowStats(Boolean show)
  389. {
  390.     /*------------------------------------------------------
  391.        Set whether or not to show stats
  392.     --------------------------------------------------------*/
  393.     ShowStats=show;
  394. }
  395.  
  396. timespec SortablePicture::GetFrameWaitTime()
  397. {
  398.     /*------------------------------------------------------
  399.        Get minimum time between frames
  400.     --------------------------------------------------------*/
  401.     return FrameWaitTime;
  402. }
  403. #ifdef SPEED_CONTROL
  404. void SortablePicture::SetFrameWaitTime(long eWait)
  405. {
  406.     /*------------------------------------------------------
  407.        Set minimum time between frames
  408.     --------------------------------------------------------*/
  409.     //bounded Assignment
  410.     FrameWaitTime.tv_nsec=eWait<=0 ? 0 : eWait>=NSEC_PER_SEC ? NSEC_PER_SEC-1 : eWait;
  411. }
  412.  
  413. timespec SortablePicture::GetSwapWaitTime()
  414. {
  415.     /*------------------------------------------------------
  416.        Get minimum time between swaps
  417.     --------------------------------------------------------*/
  418.     return SwapWaitTime;
  419. }
  420. void SortablePicture::SetSwapWaitTime(long eWait)
  421. {
  422.     /*------------------------------------------------------
  423.        Set minimum time between swaps
  424.     --------------------------------------------------------*/
  425.     //bounded Assignment 
  426.     SwapWaitTime.tv_nsec=eWait<=0 ? 0 : eWait>=NSEC_PER_SEC ? NSEC_PER_SEC-1 : eWait;
  427. }
  428. #endif
  429.